// 自定义密钥
import { sign, verify } from 'jsonwebtoken'
import { CacheState, TokenCheck } from './expireCheck'
import { State } from './utils'

const tokenCheck = new TokenCheck()

const secret = 'fl.b-18#cd_/12*+chan&koa^!.nam$milo@#$%^&*chen'

interface TokenData {
    userId: number,
    ip: string,
    time: number
}

const signToken = (data: TokenData, expiresIn = '3d') => {
    return new Promise((resolve, reject) => {
        const token = sign({
            data
        }, secret, {
            expiresIn
        })
        tokenCheck.add({ token, ...data }).then(r => {
            resolve(token)
        }).catch(e => {
            reject(e)
        })
    })
}

enum TokenStatus {
    expired = State.expired,
    unavailable = State.unavailable,
    available = State.available,
}

interface VerifyTokenRes {
    tokenStatus: TokenStatus,
    userId: number | null
    [key: string]: any
}
const verifyToken = (token: string): Promise<VerifyTokenRes> => {
    // eslint-disable-next-line no-async-promise-executor
    return new Promise(async(resolve, reject) => {
        if (token.startsWith('Bearer')) token = token.split(' ')[1]
        try {
            // @ts-expect-error 类型不对
            const data: TokenData = verify(token, secret)?.data ?? {}
            await tokenCheck.check({ userId: data.userId, token }).then(r => {
                resolve({
                    tokenStatus: r === CacheState.expired ? TokenStatus.expired : TokenStatus.available,
                    ...data
                })
            }).catch(e => {
                reject(e)
            })
            // 可用
            resolve({
                tokenStatus: TokenStatus.available,
                ...data
            })
        } catch (error) {
            try {
                // 过期
                resolve({
                    tokenStatus: TokenStatus.expired,
                    // @ts-expect-error 类型不对
                    ...(verify(token, secret)?.data ?? {})
                })
            } catch (error) {
                // 无效
                resolve({
                    tokenStatus: TokenStatus.unavailable,
                    userId: null
                })
            }
        }
    })

}

export {
    secret,
    signToken,
    TokenStatus,
    verifyToken,
    TokenData,
    VerifyTokenRes
}